Handling the arrow keys
We can use the keyCode attribute of the event object to determine which key was pressed. This will allow us to watch for codes 38 and 40, corresponding to the up and down arrow keys, and react accordingly:
$('#search-text').attr('autocomplete', 'off').keyup(function(event) {
if (event.keyCode > 40 || event.keyCode == 8) {
// Keys with codes 40 and below are special
// (enter, arrow keys, escape, etc.).
// Key code 8 is backspace.
$.ajax({
'url': '../search/autocomplete.php',
'data': {'search-text': $('#search-text').val()},
'dataType': 'json',
'type': 'GET',
'success': function(data) {
if (data.length) {
$autocomplete.empty();
$.each(data, function(index, term) {
$('<li></li>').text(term)
.appendTo($autocomplete)
.mouseover(function() {
setSelectedItem(index);
})
.click(function() {
$('#search-text').val(term);
$autocomplete.hide();
});
});
setSelectedItem(0);
}
else {
setSelectedItem(null);
}
}
});
}
else if (event.keyCode == 38 &&
selectedItem !== null) {
// User pressed up arrow.
setSelectedItem(selectedItem - 1);
event.preventDefault();
}
else if (event.keyCode == 40 &&
selectedItem !== null) {
// User pressed down arrow.
setSelectedItem(selectedItem + 1);
event.preventDefault();
}
});
Our keyup handler now checks the keyCode
that was sent, and performs the corresponding action. The AJAX requests
are now skipped if the pressed key was special, such as an arrow key or escape key. If an arrow
key is detected and the suggestion list is currently displayed, the
handler changes the selected item by 1 in the appropriate direction.
Since we wrote setSelectedItem() to clamp the values to the range of indices possible for the list, we don't have to worry about the user stepping off of either end of the list.
Inserting suggestions in the field
Next, we need to handle the Enter key (or return key on a Mac). When the suggestion list is displayed, a press of the Enter
key should populate the field with the currently selected item. Since
we are now going to be doing this in two places, we should factor the
field population routine (which we coded earlier for the mouse button)
out and into a separate function:
var populateSearchField = function() {
$('#search-text').val($autocomplete
.find('li').eq(selectedItem).text());
setSelectedItem(null);
};
Now our click handler can be a simple call to this function. We can call this function when handling the Enter key as well:
$('#search-text').keypress(function(event) {
if (event.keyCode == 13 && selectedItem !== null) {
// User pressed enter key.
populateSearchField();
event.preventDefault();
}
});
This handler is attached to the keypress event rather than keyup as before. We have to make this alteration so that we can prevent the keystroke from submitting the form. If we wait until the keyup event is triggered, the submission will already be underway.